package lookas.dao;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.LinkedList;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.Id;
import javax.persistence.IdClass;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.transaction.annotation.Transactional;

@Transactional
public class PersistenceDaoImpl implements PersistenceDao{
    private static Log    log = LogFactory.getLog(PersistenceDaoImpl.class);

    private EntityManager manager;

    public void init(){
        log.info("test");
    }

    public EntityManager getManager(){
        return manager;
    }

    @PersistenceContext(unitName = "CsvPrzewalacz")
    public void setManager(EntityManager manager){
        this.manager = manager;
    }

    public void save(Object entity){
        manager.persist(entity);
    }

    public <T>T findByExample(T object){
        try{
            return find(object);
        }catch(Exception e){
            throw new RuntimeException(e);
        }
    }

    @SuppressWarnings("unchecked")
    public <T>List<T> findAll(T o){
        Query query = manager.createQuery("select t from :class t");
        query.setParameter(":class", o.getClass());
        return query.getResultList();
    }

    @SuppressWarnings("unchecked")
    private <T>T find(T object) throws DataAccessException,
        IllegalArgumentException, IllegalAccessException,
        InstantiationException, SecurityException, NoSuchFieldException{

        Class<? extends Object> clazz = object.getClass();
        Field[] declaredFields = clazz.getDeclaredFields();

        List<Field> list = new LinkedList<Field>();
        for(Field field: declaredFields){
            if(field.getAnnotation(Id.class) != null)
                list.add(field);
        }
        Object id;
        switch(list.size()){
            case 0:
                return null;
            case 1: {
                Field field = list.get(0);
                field.setAccessible(true);
                id = field.get(object);
                break;
            }
            default: {
                Annotation annotation = clazz.getAnnotation(IdClass.class);
                if(annotation == null)
                    return null;
                Class idClass = ((IdClass)annotation).value();
                id = idClass.newInstance();
                Field[] fields = idClass.getDeclaredFields();
                for(Field field: fields){
                    Field f = clazz.getDeclaredField(field.getName());
                    f.setAccessible(true);
                    field.setAccessible(true);
                    field.set(id, f.get(object));
                }
            }
        }
        object = (T)manager.find(clazz, id);
        return object;
    }
}
